package com.yuyou.activity.comm.service.pay.service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.yuyou.activity.comm.service.entity.PayApply;
import com.yuyou.activity.comm.service.entity.PayApplyNoticeTrade;
import com.yuyou.activity.comm.service.entity.PayApplyTrade;
import com.yuyou.activity.comm.service.entity.PayRefund;
import com.yuyou.activity.comm.service.entity.PayRefundNoticeTrade;
import com.yuyou.activity.comm.service.entity.PayRefundTrade;
import com.yuyou.activity.comm.service.pay.ZyCreateOrderFail;
import com.yuyou.activity.comm.service.pay.ZyCreateOrderNotFail;
import com.yuyou.activity.comm.service.pay.ZyCreateOrderNotSucc;
import com.yuyou.activity.comm.service.pay.ZyCreateOrderSucc;
import com.yuyou.activity.comm.service.pay.ZyOrderAttach;
import com.yuyou.activity.comm.service.pay.ZyRefundOrderFail;
import com.yuyou.activity.comm.service.pay.ZyRefundOrderNotFail;
import com.yuyou.activity.comm.service.pay.ZyRefundOrderNotSucc;
import com.yuyou.activity.comm.service.pay.ZyRefundOrderSucc;
import com.yuyou.activity.comm.service.service.IPayApplyNoticeTradeService;
import com.yuyou.activity.comm.service.service.IPayApplyService;
import com.yuyou.activity.comm.service.service.IPayApplyTradeService;
import com.yuyou.activity.comm.service.service.IPayRefundNoticeTradeService;
import com.yuyou.activity.comm.service.service.IPayRefundService;
import com.yuyou.activity.comm.service.service.IPayRefundTradeService;
import com.yuyou.activity.comm.service.vo.req.ReqCreateOrder;
import com.yuyou.activity.comm.service.vo.req.ReqCreateOrderNotice;
import com.yuyou.activity.comm.service.vo.req.ReqRefundOrderNotice;
import com.yuyou.activity.comm.service.vo.req.ReqRufundOrder;
import com.yuyou.activity.util.bean.ResBoolSimpleInfo;
import com.yuyou.activity.util.enums.ZyPayEnums;
import com.yuyou.activity.util.exception.BusinessException;
import com.yuyou.activity.util.util.HttpClient;
import com.yuyou.activity.util.util.LogUtil;
import com.yuyou.activity.util.util.UUIDUtil;
import com.yuyou.activity.util.util.ZyPaySignUtil;

@Service
public class ZyPayServiceImpl implements IZyPayService{

	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	@Autowired
	private IPayApplyService payApplyService;
	@Autowired
	private IPayApplyTradeService payApplyTradeService;
	@Autowired
	private IPayApplyNoticeTradeService payApplyNoticeTradeService;

	@Autowired
	private IPayRefundService payRefundService;

	@Autowired
	private IPayRefundTradeService payRefundTradeService;
	
	@Autowired
	private IPayRefundNoticeTradeService payRefundNoticeTradeService;

	@Value("${version}")
	private String version;
	@Value("${appId}")
	private String appId;
	@Value("${appKey}")
	private String appKey;
	@Value("${merCode}")
	private String merCode;

	@Value("${createOrderUrl}")
	private String createOrderUrl;

	@Value("${queryOrderUrl}")
	private String queryOrderUrl;

	@Value("${refundOrderUrl}")
	private String refundOrderUrl;

	/**
	 * 创建订单申请
	 * 
	 * @param reqCreateOrder
	 * @return
	 * @throws Exception
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public ResBoolSimpleInfo<String> createOrder(ReqCreateOrder reqCreateOrder)
			throws Exception {
		ResBoolSimpleInfo<String> res = new ResBoolSimpleInfo<String>();
		String orderId = reqCreateOrder.getOrderId();

		Map<String, String> params = new HashMap<>();
		//支付订单流水
		params.put("id", UUIDUtil.getUUID());
		params.put("version", version);
		params.put("appId", appId);
		params.put("orderId", orderId);
		params.put("merCode", merCode);

		String sysCode = StringUtils.EMPTY;
		String projectCode = StringUtils.EMPTY;
		String amountStr=StringUtils.EMPTY;
		PayApply payApply = payApplyService.selectByOrderId(orderId);
		if (payApply != null) {

			sysCode = payApply.getSysCode();
			projectCode = payApply.getProjectCode();
			amountStr=String.valueOf(payApply.getAmount());
			params.put("amount", String.valueOf(payApply.getAmount()));
			params.put("orderName", payApply.getOrderName());
			params.put("orderContent", payApply.getOrderContent());
			params.put("orderCreateTime",
					String.valueOf(payApply.getOrderCreateTime()));
			params.put("userId", payApply.getUserId());
			params.put("returnUrl", payApply.getReturnUrl());
			params.put("attach", payApply.getAttach());
		} else {

			sysCode = reqCreateOrder.getSysCode();
			projectCode = reqCreateOrder.getProjectCode();
			amountStr=reqCreateOrder.getAmount();
			params.put("amount", reqCreateOrder.getAmount());
			params.put("orderName", reqCreateOrder.getOrderName());
			params.put("orderContent", reqCreateOrder.getOrderContent());
			params.put("orderCreateTime", String.valueOf(new Date().getTime()));
			params.put("userId", reqCreateOrder.getUserId());
			params.put("returnUrl", reqCreateOrder.getReturnUrl());
			ZyOrderAttach attach = new ZyOrderAttach(
					reqCreateOrder.getSysCode(),
					reqCreateOrder.getProjectCode());
			params.put("attach", JSON.toJSONString(attach));
		}

		if(Long.parseLong(amountStr)==0){
			throw new BusinessException("无效金额");
		}
		
		
		String sign = ZyPaySignUtil.sign(params, appKey);
		params.put("sign", sign);
		String zyResponse = HttpClient.postUtf8(createOrderUrl, params, null);
		LogUtil.info(logger, "create order "+orderId+" response："+zyResponse);

		params.put("sysCode", sysCode);
		params.put("projectCode", projectCode);
		params.put("zyRequest", JSON.toJSONString(params));
		params.put("zyResponse", zyResponse);
		LogUtil.info(logger, "createOrderUrl "+orderId+" return:" + zyResponse);
		if (zyResponse.indexOf("error") != -1) {
			ZyCreateOrderFail zyCreateOrderFail = JSONObject.parseObject(
					zyResponse, new TypeReference<ZyCreateOrderFail>() {
					});
//			res.setSuccess(false);
//			res.setMessage(zyCreateOrderFail.getError().getMessage());
			
			throw new BusinessException("创建订单失败"+zyCreateOrderFail.getError().getMessage());
			
		} else {
			ZyCreateOrderSucc zyCreateOrderSucc = JSONObject.parseObject(
					zyResponse, new TypeReference<ZyCreateOrderSucc>() {
					});
			res.setSuccess(true);
			res.setData(zyCreateOrderSucc.getResult().getCounterUrl());
			String payOrderId = zyCreateOrderSucc.getResult().getPayOrderId();
			// zyCreateOrderSucc.getResult().getCounterUrl();
			packPayApply(params, payOrderId);
		}
		return res;

	}

	public void packPayApply(Map<String, String> params, String payOrderId) {

		PayApply exist = payApplyService.selectByOrderId(params.get("orderId"));
		Long payApplyId = null;
		// 订单申请
		if (exist == null) {
			PayApply payApply = new PayApply();
			payApply.setSysCode(params.get("sysCode"));
			payApply.setProjectCode(params.get("projectCode"));
			payApply.setOrderId(params.get("orderId"));
			payApply.setAmount(Long.parseLong(params.get("amount")));
			payApply.setOrderName(params.get("orderName"));
			payApply.setOrderContent(params.get("orderContent"));
			payApply.setOrderCreateTime(Long.parseLong(params
					.get("orderCreateTime")));
			payApply.setUserId(params.get("userId"));
			payApply.setReturnUrl(params.get("returnUrl"));
			payApply.setAttach(params.get("attach"));
			payApply.setStatus(ZyPayEnums.payApplyStatus.INTI.getValue());
			payApply.setPayOrderId(payOrderId);
			payApplyService.add(payApply);
			payApplyId = payApply.getPayApplyId();
		} else {
			payApplyId = exist.getPayApplyId();
		}
		// 订单申请流水
		PayApplyTrade payApplyTrade = new PayApplyTrade();
		payApplyTrade.setTradeSn(params.get("id"));
		payApplyTrade.setPayApplyId(payApplyId);
		payApplyTrade.setOrderId(params.get("orderId"));
		payApplyTrade.setZyRequest(params.get("zyRequest"));
		payApplyTrade.setZyResponse(params.get("zyResponse"));
		payApplyTradeService.add(payApplyTrade);
	}

	/**
	 * 查询订单
	 * 
	 * @param orderId
	 * @return
	 * @throws Exception
	 */
	@Override
	public ResBoolSimpleInfo<String> queryOrder(String orderId)
			throws Exception {
		ResBoolSimpleInfo<String> res = new ResBoolSimpleInfo<String>();

		PayApply exist = payApplyService.selectByOrderId(orderId);
		if (exist == null) {
			res.setMessage("无效订单：找不到业务订单");
			res.setSuccess(false);
			return res;
		}
//		if (exist.getStatus() == ZyPayEnums.payApplyStatus.SUCCESS.getValue()) {
//			res.setMessage("订单已支付");
//			res.setSuccess(true);
//			return res;
//		}
		Map<String, String> params = new HashMap<>();
		params.put("payOrderId", exist.getPayOrderId());

		String s = HttpClient.get(queryOrderUrl, params);
		if (StringUtils.isEmpty(s)) {
			res.setSuccess(false);
		} else {
			PayApply update = new PayApply();
			update.setPayApplyId(exist.getPayApplyId());
			update.setStatus(ZyPayEnums.payApplyStatus.SUCCESS.getValue());
			payApplyService.updateByPrimaryKeySelective(update);
			res.setSuccess(true);
		}

		return res;

	}

	/**
	 * 订单申请通知
	 * 
	 * @param reqCreateOrderNotice
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public ResBoolSimpleInfo<String> createOrderNotice(
			ReqCreateOrderNotice reqCreateOrderNotice) {
		ResBoolSimpleInfo<String> res = new ResBoolSimpleInfo<String>();
		String orderId = reqCreateOrderNotice.getOrderId();
		PayApply exist = payApplyService.selectByOrderId(orderId);
		if (exist != null) {
			if (exist.getStatus().intValue() != ZyPayEnums.payApplyStatus.SUCCESS
					.getValue()) {
				// 支付成功才有通知，reqCreateOrderNotice.getPayStatus()==1
				PayApply updatePayApply = new PayApply();
				updatePayApply.setPayApplyId(exist.getPayApplyId());
				updatePayApply.setStatus(ZyPayEnums.payApplyStatus.SUCCESS
						.getValue());
				payApplyService.updateByPrimaryKeySelective(updatePayApply);
			}

			PayApplyNoticeTrade noticeTrace = new PayApplyNoticeTrade();
			noticeTrace.setTradeSn(reqCreateOrderNotice.getTradeSn());
			noticeTrace.setOrderId(orderId);
			noticeTrace.setPayOrderId(reqCreateOrderNotice.getPayOrderId());
			noticeTrace.setPayStatus(Integer.parseInt(reqCreateOrderNotice
					.getPayStatus()));
			noticeTrace.setAttach(reqCreateOrderNotice.getAttach());
			// noticeTrace.setCode();
			noticeTrace.setZyRequest(reqCreateOrderNotice.getZyRequest());
			noticeTrace.setZyResponse(ZyCreateOrderNotSucc.getRes());
			payApplyNoticeTradeService.insert(noticeTrace);
			res.setData(ZyCreateOrderNotSucc.getRes());
			res.setSuccess(true);
		} else {
			res.setMessage(ZyCreateOrderNotFail
					.getRes(ZyPayEnums.payApplyNoticeCode._4012.getKey()));
			res.setSuccess(false);
		}
		return res;
	}

	/**
	 * 全额退款申请
	 * 
	 * @param reqRufundOrder
	 * @return
	 * @throws Exception 
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public ResBoolSimpleInfo<Integer> refundAllOrder(ReqRufundOrder reqRufundOrder) throws Exception {
		ResBoolSimpleInfo<Integer> res = new ResBoolSimpleInfo<Integer>();

		// 是否存在业务订单
		PayApply existPayApply = payApplyService.selectByOrderId(reqRufundOrder.getOrderId());
		if (existPayApply == null) {
			res.setSuccess(false);
			res.setMessage("无效订单：找不到业务订单");
			 return res;
		}

		PayRefund existPayRefund = payRefundService.selectByOrderId(reqRufundOrder.getOrderId());
		if (existPayRefund != null) {
			// 已经申请，返回申请状态
			res.setSuccess(true);
			res.setData(existPayRefund.getRefundStatus());
			 return res;
		}

		Map<String, String> params = new HashMap<>();
		params.put("id", UUIDUtil.getUUID());
		params.put("version", version);
		params.put("appId", appId);
		params.put("refundId", reqRufundOrder.getRefundId());
		params.put("orderId", reqRufundOrder.getOrderId());
		params.put("refundAmount", String.valueOf(existPayApply.getAmount()));
		params.put("bizApprover", "yygz");
		params.put("bizApproveTime", String.valueOf(new Date().getTime()));
		ZyOrderAttach attach = new ZyOrderAttach(
				reqRufundOrder.getSysCode(),
				reqRufundOrder.getProjectCode());
		params.put("attach", JSON.toJSONString(attach));
		String sign = ZyPaySignUtil.sign(params, appKey);
		params.put("sign", sign);

		String zyResponse = HttpClient.postUtf8(refundOrderUrl, params, null);
		params.put("zyRequest", JSON.toJSONString(params));
		params.put("zyResponse", zyResponse);
		LogUtil.info(logger, "refundAllOrder "+reqRufundOrder.getRefundId()+" return:" + zyResponse);
		if (zyResponse.indexOf("error") != -1) {
			LogUtil.error(logger, "退款申请失败：" + zyResponse);
			// 告警todo
			ZyRefundOrderFail zyRefundOrderFail = JSONObject.parseObject(
					zyResponse, new TypeReference<ZyRefundOrderFail>() {
					});
//				res.setSuccess(false);
//				res.setMessage(zyRefundOrderFail.getError().getMessage());
			throw new BusinessException("退款申请失败"+zyRefundOrderFail.getError().getMessage());
		} else {
			ZyRefundOrderSucc zyRefundOrderSucc = JSONObject.parseObject(
					zyResponse, new TypeReference<ZyRefundOrderSucc>() {
					});
			String refundOrderId = zyRefundOrderSucc.getResult()
					.getRefundOrderId();
			packRefundApply(params, existPayApply, reqRufundOrder.getRefundId(), refundOrderId);
			res.setData(ZyPayEnums.payRufundStatus.INTI.getValue());
			res.setSuccess(true);
		}

		return res;
	}

	@Override
	public ResBoolSimpleInfo<Integer> refundPartOrder(ReqRufundOrder reqRufundOrder, Long amount) throws Exception {
		ResBoolSimpleInfo<Integer> res = new ResBoolSimpleInfo<Integer>();

		// 是否存在业务订单
		PayApply existPayApply = payApplyService.selectByOrderId(reqRufundOrder.getOrderId());
		if (existPayApply == null) {
			res.setSuccess(false);
			res.setMessage("无效订单：找不到业务订单");
			return res;
		}

		//退款金额大于实际支付金额
		if(existPayApply.getAmount().longValue() < amount.longValue()){
			res.setSuccess(false);
			res.setMessage("无效订单：退款金额大于实际支付金额");
			return res;
		}

		PayRefund existPayRefund = payRefundService.selectByOrderId(reqRufundOrder.getOrderId());
		if (existPayRefund != null) {
			// 已经申请，返回申请状态
			res.setSuccess(true);
			res.setData(existPayRefund.getRefundStatus());
			return res;
		}

		Map<String, String> params = new HashMap<>();
		params.put("id", UUIDUtil.getUUID());
		params.put("version", version);
		params.put("appId", appId);
		params.put("refundId", reqRufundOrder.getRefundId());
		params.put("orderId", reqRufundOrder.getOrderId());
		params.put("refundAmount", String.valueOf(amount));
		params.put("bizApprover", "yygz");
		params.put("bizApproveTime", String.valueOf(new Date().getTime()));
		ZyOrderAttach attach = new ZyOrderAttach(
				reqRufundOrder.getSysCode(),
				reqRufundOrder.getProjectCode());
		params.put("attach", JSON.toJSONString(attach));
		String sign = ZyPaySignUtil.sign(params, appKey);
		params.put("sign", sign);

		String zyResponse = HttpClient.postUtf8(refundOrderUrl, params, null);
		params.put("zyRequest", JSON.toJSONString(params));
		params.put("zyResponse", zyResponse);
		LogUtil.info(logger, "refundAllOrder "+reqRufundOrder.getRefundId()+" return:" + zyResponse);
		if (zyResponse.indexOf("error") != -1) {
			LogUtil.error(logger, "退款申请失败：" + zyResponse);
			// 告警
			ZyRefundOrderFail zyRefundOrderFail = JSONObject.parseObject(
					zyResponse, new TypeReference<ZyRefundOrderFail>() {
					});
			throw new BusinessException("退款申请失败"+zyRefundOrderFail.getError().getMessage());
		} else {
			ZyRefundOrderSucc zyRefundOrderSucc = JSONObject.parseObject(
					zyResponse, new TypeReference<ZyRefundOrderSucc>() {
					});
			String refundOrderId = zyRefundOrderSucc.getResult()
					.getRefundOrderId();
			packRefundApply(params, existPayApply, reqRufundOrder.getRefundId(), refundOrderId);
			res.setData(ZyPayEnums.payRufundStatus.INTI.getValue());
			res.setSuccess(true);
		}

		return res;
	}


	@Transactional
	public void packRefundApply(Map<String, String> params, PayApply payApply,
			String refundId, String refundOrderId) {

		PayRefund exist = payRefundService.selectByRefundId(params
				.get("refundId"));
		// 退款申请
		Long payRefundId = null;
		if (exist == null) {
			PayRefund payRefund = new PayRefund();
			payRefund.setAttach(params.get("attach"));
			payRefund.setOrderId(payApply.getOrderId());
			payRefund.setPayOrderId(payApply.getPayOrderId());
			payRefund.setRefundAmount(params.containsKey("refundAmount")? Long.valueOf(params.get("refundAmount")) : payApply.getAmount());
			payRefund.setRefundId(refundId);
			payRefund.setRefundOrderId(refundOrderId);
			payRefund.setRefundStatus(ZyPayEnums.payRufundStatus.INTI
					.getValue());
			payRefund.setTotalAmount(payApply.getAmount());
			payRefundService.add(payRefund);
			payRefundId = payRefund.getPayRefundId();
		} else {
			payRefundId = exist.getPayRefundId();
		}
		// 退款申请流水
		PayRefundTrade payRefundTrade = new PayRefundTrade();
		payRefundTrade.setTradeSn(params.get("id"));
		payRefundTrade.setPayRefundId(payRefundId);
		payRefundTrade.setRefundId(refundId);
		// payRefundTrade.setCode(code);
		payRefundTrade.setZyRequest(params.get("zyRequest"));
		payRefundTrade.setZyResponse(params.get("zyResponse"));
		payRefundTradeService.add(payRefundTrade);

	}

	/**
	 * 退款通知
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public ResBoolSimpleInfo<Integer> refundOrderNotice(
			ReqRefundOrderNotice reqRefundOrderNotice) {
		ResBoolSimpleInfo<Integer> res=new ResBoolSimpleInfo<Integer>();
		PayRefund exist=payRefundService.selectByRefundId(reqRefundOrderNotice.getRefundId());
		if(exist!=null){
			//更新退款状态
			PayRefund upPayRefund = new PayRefund();
			upPayRefund.setPayRefundId(exist.getPayRefundId());
			upPayRefund.setRefundStatus(Integer.parseInt(reqRefundOrderNotice.getRefundStatus()));
			payRefundService.updateByPrimaryKeySelective(upPayRefund);
			
			//更新退款通知流水
			PayRefundNoticeTrade reNoticeTrace = new PayRefundNoticeTrade();
			reNoticeTrace.setTradeSn(reqRefundOrderNotice.getTradeSn());
			reNoticeTrace.setRefundId(reqRefundOrderNotice.getRefundId());
			reNoticeTrace.setRefundOrderId(reqRefundOrderNotice.getRefundOrderId());
			reNoticeTrace.setRefundStatus(Integer.parseInt(reqRefundOrderNotice
					.getRefundStatus()));
			reNoticeTrace.setRefundAmount(Long.parseLong(reqRefundOrderNotice.getRefundAmount()));
			reNoticeTrace.setAttach(reqRefundOrderNotice.getAttach());
			// noticeTrace.setCode();
			reNoticeTrace.setZyRequest(reqRefundOrderNotice.getZyRequest());
			reNoticeTrace.setZyResponse(ZyRefundOrderNotSucc.getRes());
			payRefundNoticeTradeService.add(reNoticeTrace);
			
			
			res.setData(upPayRefund.getRefundStatus());
			res.setSuccess(true);		
			return res;
			
		} else {
			res.setMessage(ZyRefundOrderNotFail
					.getRes(ZyPayEnums.payRufundNoticeCode._4012.getKey()));
			res.setSuccess(false);
			return res;
		}
		
		
	}
	
	
	
	
	
	
	
	
	
	
	
	
}